<template>
  <div class="testPlatform-container">
    <MCard>
      <template #header>
        <div class="flex gap-20px items-center">
          <span>查询节点</span>
        </div>
      </template>
      <div>
        <el-form :model="queryNodeConfig" :inline="true">
          <el-form-item label="节点ID">
            <el-input v-model="queryNodeConfig.nodeId" placeholder="输入节点ID"></el-input>
          </el-form-item>
          <el-form-item label="节点IP">
            <el-input v-model="queryNodeConfig.ipAddress" placeholder="输入节点IP"></el-input>
          </el-form-item>
          <el-form-item label="是否注入">
            <MSelect v-model="queryNodeConfig.faultInjection"  v-bind="faultInjectionOptions"></MSelect>
          </el-form-item>
          <el-form-item label="注入类型">
            <MSelect v-model="queryNodeConfig.injectionType"  v-bind="injectionTypeOptions"></MSelect>
          </el-form-item>        
          <el-form-item>
            <div class="global_btn" @click="getNodeList" style="width: 100px;">查询</div>
          </el-form-item>
        </el-form>
      </div>
    </MCard>
    <MCard>
      <template #header>
        <div class="flex gap-20px items-center">
          <span>节点列表</span>
          <el-radio-group v-model="nodeChooseConfig.nodeTypeRadio" @change="handleTypeChange">
            <el-radio value="3" size="large">全部节点</el-radio>
            <el-radio value="1" size="large">真实节点</el-radio>
            <el-radio value="0" size="large">虚拟节点</el-radio>
          </el-radio-group>
        </div>
      </template>
      <div class="flex gap-20px items-center">
        <div class="global_btn" style="width: 100px;" v-globalBtnLoading="handleAllInject">一键注入</div>
        <div class="global_btn" style="width: 100px;" v-globalBtnLoading="handleStop">一键停止</div>
        <div class="tech-checkbox" @click="toggleSelectAll">
           <div class="checkbox-inner" :class="{'is-checked': nodeChooseConfig.isSelectAll}">
             <div class="check-mark" v-if="nodeChooseConfig.isSelectAll"></div>
           </div>
           <span class="checkbox-label">全选</span>
         </div>
      </div>
      <div class="grid grid-cols-4 gap-10px m-t-20px">
        <div class="deployedNodeItem" v-for="(item, index) in nodeList" :key="index">
          <div class="node-header">
            <div class="tech-checkbox" @click="toggleItemSelect(item)">
              <div class="checkbox-inner" :class="{ 'is-checked': item.isSelect }">
                <div class="check-mark" v-if="item.isSelect"></div>
              </div>
            </div>
            <span class="node-id">节点ID: {{ item.nodeId }}</span>
            <div style="margin-left: auto;" v-if="item.faultInjection === 1">
              <img src="@/assets/imgs/warningSigns.png" alt="">
            </div>
          </div>
          <div class="node-divider"></div>
          <div class="node-content">
            <div class="node-info">
              <div class="info-grid">
                <div class="info-item">
                  <span class="info-label">节点类型:</span>
                  <span class="info-value" :class="item.type === 1 || item.type === 2 ? 'real-node' : 'virtual-node'">{{
                    item.type === 1 ? '真实节点' : item.type === 0 ? '虚拟节点' : '' }}</span>
                </div>
                <div class="info-item" v-for="(subItem, key) in nodeListItems" :key="key">
                  <span class="info-label">{{ subItem.label }}:</span>
                  <span class="info-value" :class="getStatusClass(key, item[key])">{{ getDisplayValue(key, item[key])
                    }}</span>
                </div>
              </div>
              <div class="status-indicator" :class="item.connectionStatus === 1 ? 'connected' : 'disconnected'">
                <img :src="item.imgUrl" alt="" class="status-icon">
                <div class="status-pulse"></div>
                <div class="status-text">{{ item.connectionStatus === 1 ? '已连接' : '未连接' }}</div>
              </div>
            </div>
            <div class="node-actions">
              <div class="global_btn" v-if="item.connectionStatus === 1&&item.faultInjection === 0" @click="handleInjectConfig(item)">故障注入配置</div>
              <div class="global_btn" v-if="item.connectionStatus === 1&&item.faultInjection === 1" @click="handleStopInject(item)">停止注入</div>
            </div>
          </div>
        </div>
      </div>
      <div class="flex justify-center m-t-20px">
        <el-pagination 
        v-model:currentPage="pageData.currentPage" 
        v-model:page-size="pageData.pageSize"
          :page-sizes="[3, 5, 7, 10]" 
          layout="total, prev, pager, next, jumper" 
          :total="pageData.total"
          @size-change="getNodeList" 
          @current-change="getNodeList" 
          size="small" />
      </div>
    </MCard>
    <MDialog
      v-bind="injectConfigDialogData"
      v-model:dialogVisible="injectConfigDialogData.visible"
    >
    <template #content>
      <el-form
       labelWidth="150px"
       labelPosition="left"
       :rules="injectConfigRules"
       ref="injectConfigFormRef"
       :model="injectConfigForm"
       :hide-required-asterisk="true"
      >
        <el-form-item label="注入配置项选择" prop="injectionType">
           <MSelect 
            v-bind="injectOptions"
            v-model="injectConfigForm.injectionType"
            />
        </el-form-item>
        <template v-if="injectConfigForm.injectionType !== null">
          <!-- 普通单值注入类型 -->
          <template v-if="[1, 2, 3].includes(injectConfigForm.injectionType)">
            <el-form-item 
              :prop="injectionTypeConfig[injectConfigForm.injectionType as number].field"
              :label="injectionTypeConfig[injectConfigForm.injectionType as number]?.label" 
              v-if="injectConfigForm.injectionType !== null && injectionTypeConfig[injectConfigForm.injectionType as number]"
            >
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm[injectionTypeConfig[injectConfigForm.injectionType as number].field]"
                :placeholder="injectionTypeConfig[injectConfigForm.injectionType as number].placeholder || ''"
              ></el-input>
              <span class="form-hint" v-if="injectionTypeConfig[injectConfigForm.injectionType as number].hint">
                {{ injectionTypeConfig[injectConfigForm.injectionType as number].hint }}
              </span>
            </el-form-item>
          </template>        
          <!-- 带宽限制 -->
          <template v-if="injectConfigForm.injectionType === 4">
            <el-form-item label="带宽速率" prop="bandwidthRate">
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm.bandwidthRate"
                placeholder="输入带宽限制，如：1Mbps"
              ></el-input>
              <span class="form-hint">单位可为Kbps或Mbps</span>
            </el-form-item>
            <el-form-item label="突发大小" prop="burstSize">
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm.burstSize"
                placeholder="输入突发大小"
              ></el-input>
            </el-form-item>
            <el-form-item label="延迟时间" prop="latencyTime">
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm.latencyTime"
                placeholder="输入延迟时间，如：100ms"
              ></el-input>
            </el-form-item>
          </template>          
          <!-- 数据包乱序 -->
          <template v-if="injectConfigForm.injectionType === 5">
            <el-form-item label="乱序率" prop="reorderRate">
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm.reorderRate"
                placeholder="输入乱序率，如：20%"
              ></el-input>
              <span class="form-hint">乱序率范围：0-100%</span>
            </el-form-item>
            <el-form-item label="乱序间隔" prop="reorderGap">
              <el-input 
                style="width: 300px;" 
                v-model="injectConfigForm.reorderGap"
                placeholder="输入乱序间隔"
              ></el-input>
            </el-form-item>
          </template>
        </template>
        <el-form-item label="注入端口" prop="port">
          <el-input v-model="injectConfigForm.port" style="width: 300px;" placeholder="请输入注入端口"></el-input>
        </el-form-item>
      </el-form>
    </template>
    <template #footer>
      <div class="global_btn" style="width: 100px;" v-globalBtnLoading="{
        handler: handleInject,
        text: '注入中...'
      }">一键注入</div>
    </template>
    </MDialog>
  </div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  name: 'TestPlatform',
})
</script>

<script setup lang="ts">
import { nodeManagementApi } from '@/api/nodeManagement'
import connectedImg from "@/assets/imgs/connected.png"
import disconnectedImg from "@/assets/imgs/disconnected.png"
import { ElNotificationFn } from "@/utils/computedUtils"
import { useRouter } from 'vue-router'
import dayjs from "dayjs"
const router = useRouter()
const nodeList: any = ref([])
const initialNodeList: any = ref([])
const pageData = ref({
  currentPage: 1,
  pageSize: 8,
  total: 0,
})
const currentNode = ref<any>(null)
const nodeListItems = ref<any>({
  ipAddress: {
    label: "节点IP",
    isCustom: false
  },
  faultInjection: {
    label: "故障注入",
    isCustom: true,
    valueMap: {
      "0": {
        text: "未注入",
        class: "inject-success"
      },
      "1": {
        text: "已注入",
        class: "inject-error"
      }
    }
  },
  injectionPort: {
    label: "注入端口",
    isCustom: false
  },
  injectionType: {
    label: "注入类型",
    isCustom: true,
    valueMap: {
      "0": {
        text: "模拟延时",
        class: "status-success"
      },
      "1": {
        text: "丢包模拟",
        class: "status-error"
      },
      "2": {
        text: "数据包重复",
        class: "status-error"
      },
      "3": {
        text: "数据包乱序",
        class: "status-error"
      },
      "4": {
        text: "带宽限制故障",
        class: "status-error"
      },
      default: {
        text: "未选择",
        class: "status-error"
      }
    }
  }
})
const nodeChooseConfig = ref<any>({
  nodeTypeRadio: "3",
  isSelectAll: false
})
const queryNodeConfig = ref<any>({
  nodeId: "",
  ipAddress: "",
  injectionType: "",
  port: "",
  faultInjection: ""
})
const injectionTypeOptions = ref<any>({
  options: [
   {
    label: "模拟延时",
    value: 0
   },
   {
    label: "丢包模拟",
    value: 1
   },
   {
    label: "数据包重复",
    value: 2
   },
   {
    label: "数据包乱序",
    value: 3
   },
   {
    label: "带宽限制故障",
    value: 4
   }
  ],
  placeholder: "选择注入类型",
  width: "200px"
})
const faultInjectionOptions = ref<any>({
  options: [
    {
      label: "已注入",
      value: 1
    },
    {
      label: "未注入",
      value: 0
    }
  ],
  placeholder: "选择故障注入",
  width: "200px"
})
const getNodeList = async () => {
  const { data } = await nodeManagementApi.getNodeListExcludeHost({
    ...pageData.value,
    ...queryNodeConfig.value
  })
  initialNodeList.value = data.records.map((item: any) => {
    return {
      ...item,
      imgUrl: item.connectionStatus === 1 ? connectedImg : disconnectedImg,
      updateTime: dayjs(item.updateTime).format("YYYY-MM-DD HH:mm:ss"),
    }
  })
  nodeList.value = initialNodeList.value
  pageData.value.total = data.total
}
function toggleItemSelect(item: any) {
  item.isSelect = !item.isSelect
  nodeChooseConfig.value.isSelectAll = nodeList.value.every((node:any)=>node.isSelect)
}
function handleTypeChange(val: string | number | boolean | undefined) {
  const valStr = String(val)
  if (valStr === "3") {
    nodeList.value = initialNodeList.value
    return
  }
  nodeList.value = initialNodeList.value.filter((item: any) => {
    return item.type == valStr
  })
}
function getDisplayValue(key: string, value: any): string {
  const item = nodeListItems.value[key];
  if (!item.isCustom) return value || '';
  if (item.valueMap) {
    const mapItem = item.valueMap[String(value)] || item.valueMap.default;
    return mapItem.text;
  }
  return value || '';
}
function getStatusClass(key: string, value: any): string {
  const item = nodeListItems.value[key];
  if (!item.isCustom) return '';
  if (item.valueMap) {
    const mapItem = item.valueMap[String(value)] || item.valueMap.default;
    return mapItem.class;
  }
  return '';
}
async function handleStop() {
  try {
    if(!nodeList.value.some((item:any)=>item.isSelect)){
      ElNotificationFn("warning", "至少选择一个节点")
      return
    }
    if(!nodeList.value.some((item:any)=>item.isSelect && item.faultInjection === 1)){
      ElNotificationFn("warning", "只能选择已注入的节点")
      return
    }
    const chooseNodeList = nodeList.value.filter((item:any)=>item.isSelect && item.faultInjection === 1)
    const list = chooseNodeList.map((item:any)=>({
      nodeId: item.nodeId,
      ipAddress: item.ipAddress,
      injectionType: item.type,
      port: item.injectionPort
    }))
    await nodeManagementApi.postStopInjectFault(list)
    ElNotificationFn("success", "停止注入成功")
    getNodeList()
  } catch (error) { }
}
function toggleSelectAll(){
  nodeList.value.forEach((item:any)=>{
    item.isSelect = !nodeChooseConfig.value.isSelectAll
  })
  nodeChooseConfig.value.isSelectAll = !nodeChooseConfig.value.isSelectAll
}
const isAllInject = ref(false)
function handleAllInject(){
  if(nodeList.value.every((item:any)=>!item.isSelect)){
    ElNotificationFn("warning", "至少选中一个节点")
    return
  }
  if(nodeList.value.some((item:any)=>item.isSelect && item.connectionStatus === 0)){
    ElNotificationFn("warning", "只能选择已连接的节点")
    return
  }
  isAllInject.value = true
  const chooseNodeList = nodeList.value.filter((item:any)=>item.isSelect && item.connectionStatus === 1)
  injectConfigDialogData.value.visible = true
  injectConfigForm.value.nodeId = chooseNodeList.map((item:any)=>item.nodeId)
  injectConfigForm.value.ipAddress = chooseNodeList.map((item:any)=>item.ipAddress)
}

function handleInjectConfig(item:any){
  currentNode.value = item
  injectConfigDialogData.value.visible = true
  injectConfigFormRef.value.resetFields()
}
async function handleStopInject(item:any){
  try {
    await nodeManagementApi.postStopInjectFault([
      {
        nodeId: item.nodeId,
        ipAddress: item.ipAddress,
        injectionType: item.type,
        port: item.injectionPort
      }
    ])
    ElNotificationFn("success", "停止注入成功")
    getNodeList()
  } catch (error) { }
}
async function handleInject(){
  try {
    await injectConfigFormRef.value.validate()
    if(!injectConfigForm.value.injectionType) {
      ElNotificationFn("warning", "选择注入配置项")
      return
    }
    const currentConfig = injectionTypeConfig[injectConfigForm.value.injectionType]
    let params: any = {
      nodeIds: isAllInject.value ? injectConfigForm.value.nodeId : [currentNode.value.nodeId],
      ips: isAllInject.value ? injectConfigForm.value.ipAddress : [currentNode.value.ipAddress],
      port: Number(injectConfigForm.value.port),
      injectionType: currentConfig.injectionType
    }
    // 处理不同的注入类型
    if (injectConfigForm.value.injectionType === 4) {
      params.bandwidthRate = Number(injectConfigForm.value.bandwidthRate)
      params.burstSize = Number(injectConfigForm.value.burstSize || 0)
      params.latencyTime = Number(injectConfigForm.value.latencyTime || 0)
    } else if (injectConfigForm.value.injectionType === 5) {
      params.reorderRate = Number(injectConfigForm.value.reorderRate)
      params.reorderGap = Number(injectConfigForm.value.reorderGap || 0)
    } else {
      // 其他普通单值参数类型
      const fieldName = String(currentConfig.field)
      const fieldValue = injectConfigForm.value[fieldName]
      params[fieldName] = fieldValue
    }
    await nodeManagementApi.postInjectFault(params)
    injectConfigDialogData.value.visible = false
    isAllInject.value = false
    ElNotificationFn("success", "故障注入配置成功")
    getNodeList()
  } catch (error) { }
}
const injectConfigDialogData = ref<any>({
  visible: false,
  title: '故障注入配置',
  content: '故障注入配置',
})
interface InjectionTypeInfo {
  label: string;
  field: string | string[];
  placeholder: string;
  hint: string;
  injectionType: string | number;
}
interface InjectionTypeConfig {
  [key: number]: InjectionTypeInfo;
}
const injectionTypeConfig: InjectionTypeConfig = {
  1: {
    label: '丢包模拟',
    field: 'lossRate',
    placeholder: '输入丢包率，如：30%',
    hint: '丢包率范围：0-100%',
    injectionType: 1
  },
  2: {
    label: '数据包重复',
    field: 'duplicationRate',
    placeholder: '输入重复率，如：20%',
    hint: '重复率范围：0-100%',
    injectionType: 2
  },
  3: {
    label: '延时模拟',
    field: 'delayTime',
    placeholder: '请输入延时时间，如：100ms',
    hint: '建议延时范围：10-1000ms',
    injectionType: 0
  },
  4: {
    label: '带宽限制',
    field: 'bandwidthRate',
    placeholder: '输入带宽限制，如：1Mbps',
    hint: '单位可为Kbps或Mbps',
    injectionType: 4
  },
  5: {
    label: '数据包乱序',
    field: 'reorderRate',
    placeholder: '输入乱序率，如：20%',
    hint: '乱序率范围：0-100%',
    injectionType: 3
  }
}
const injectConfigForm = ref<any>({
  injectPort: '',
  injectionType: null as number | null,
  delayTime:"",//延时时间
  lossRate:"",//丢包率
  duplicationRate:"",//重复率
  bandwidthRate:"",//带宽限制
  burstSize:"",//突发大小
  latencyTime:"",//延迟时间
  reorderRate:"",//乱序率
  reorderGap:"",
})
const injectConfigFormRef = ref<any>(null)
function validatePort(rule:any,value:any,callback:any){
  if(!value){
    callback(new Error("输入注入端口"))
  }else if(value==8080){
    callback(new Error("注入端口不能为8080"))
  }else {
    callback()
  }
}
const injectConfigRules = ref<any>({
  port: [{validator:validatePort,trigger:'blur' }],
  injectionType: [{required: true, message: '选择注入类型', trigger: 'blur'}],
  bandwidthRate: [{required: true, message: '输入带宽限制', trigger: 'blur'}],
  reorderRate: [{required: true, message: '输入乱序率', trigger: 'blur'}],
  delayTime: [{required: true, message: '输入延时时间', trigger: 'blur'}],
  lossRate: [{required: true, message: '输入丢包率', trigger: 'blur'}],
  duplicationRate: [{required: true, message: '输入重复率', trigger: 'blur'}],
  burstSize: [{required: true, message: '输入突发大小', trigger: 'blur'}],
  latencyTime: [{required: true, message: '输入延迟时间', trigger: 'blur'}],
  reorderGap: [{required: true, message: '输入乱序间隔', trigger: 'blur'}],
})
const injectOptions = ref<any>({
   options: [
    {
      label: '丢包模拟',
      value: 1
    },
    {
      label: '数据包重复',
      value: 2
    },
    {
      label: '延时模拟',
      value: 3
    },
    {
      label: '带宽限制',
      value: 4
    },
    {
      label: '数据包乱序',
      value: 5
    }
   ],
  placeholder: "选择注入类型",
  width: "200px"
})
function handleInjectionTypeChange(val: number) {
  injectConfigForm.value.packet_loss = ""
  injectConfigForm.value.packet_duplication = ""
  injectConfigForm.value.delay_simulation = ""
  injectConfigForm.value.bandwidth_failure = ""
}
watch(()=>injectConfigForm.value.injectionType, (newVal) => {
  handleInjectionTypeChange(newVal)
})

onMounted(() => {
  getNodeList()
})
</script>

<style lang="scss" scoped>
@import "@/styles/card.scss";
@import "@/styles/pagination.scss";
@import "@/styles/input.scss";
@import "@/styles/form.scss";

.testPlatform-container {
  width: 100%;
  height: 100%;

  .deployedNodeItem {
    background: linear-gradient(180deg,
        rgba(22, 30, 45, 0.8) 0%,
        rgba(18, 28, 40, 0.85) 50%,
        rgba(15, 25, 38, 0.8) 100%);
    border: 1px solid rgba(35, 85, 140, 0.5);
    border-radius: 4px;
    box-shadow:
      inset 0 0 15px rgba(0, 140, 255, 0.08),
      0 0 10px rgba(0, 0, 0, 0.4),
      0 0 8px rgba(0, 150, 255, 0.1);
    overflow: hidden;
    position: relative;
    transition: all 0.3s ease;

    &::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 1px;
      background: linear-gradient(90deg,
          transparent,
          rgba(0, 170, 255, 0.5),
          transparent);
      opacity: 0.7;
      z-index: 2;
    }

    &::after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-image:
        linear-gradient(rgba(40, 100, 180, 0.02) 1px, transparent 1px),
        linear-gradient(90deg, rgba(40, 100, 180, 0.02) 1px, transparent 1px);
      background-size: 20px 20px;
      pointer-events: none;
      opacity: 0.5;
      z-index: 1;
    }

    &:hover {
      transform: translateY(-2px);
      box-shadow:
        inset 0 0 20px rgba(0, 140, 255, 0.12),
        0 5px 15px rgba(0, 0, 0, 0.4),
        0 0 15px rgba(0, 150, 255, 0.15);

      .node-id {
        color: #fff;
        text-shadow: 0 0 8px rgba(0, 180, 255, 0.6);
      }

      .node-divider {
        background: linear-gradient(90deg,
            transparent,
            rgba(0, 180, 255, 0.6),
            transparent);
        box-shadow: 0 0 8px rgba(0, 180, 255, 0.4);
      }
    }

    .node-header {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 12px;
      position: relative;
      z-index: 2;
    }

    .node-id {
      color: rgba(255, 255, 255, 0.9);
      font-family: 'Consolas', monospace;
      font-size: 14px;
      font-weight: 500;
      letter-spacing: 0.5px;
      text-shadow: 0 0 5px rgba(0, 140, 255, 0.3);
      transition: all 0.3s;
    }

    .node-divider {
      height: 1px;
      width: 90%;
      margin: 0 auto;
      background: linear-gradient(90deg,
          transparent,
          rgba(0, 150, 255, 0.4),
          transparent);
      transition: all 0.3s;
    }

    .node-content {
      padding: 12px;
      position: relative;
      z-index: 2;
      display: flex;
      flex-direction: column;
      gap: 15px;
    }

    .node-info {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .info-grid {
      display: grid;
      gap: 8px;
    }

    .info-item {
      display: flex;
      align-items: center;
      gap: 8px;

      .real-node {
        color: rgba(0, 255, 80, 0.9);
        text-shadow:
          0 0 5px rgba(0, 255, 80, 0.5),
          0 0 10px rgba(0, 255, 80, 0.3);
        font-weight: 500;
        letter-spacing: 0.5px;
        position: relative;
        padding-left: 15px;
      }

      .virtual-node {
        color: rgba(255, 80, 80, 0.9);
        text-shadow:
          0 0 5px rgba(255, 80, 80, 0.5),
          0 0 10px rgba(255, 80, 80, 0.3);
        font-weight: 500;
        letter-spacing: 0.5px;
        position: relative;
        padding-left: 15px;
      }
    }

    .info-label {
      color: rgba(100, 180, 255, 0.9);
      font-size: 13px;
      font-weight: 500;
    }

    .info-value {
      color: rgba(255, 255, 255, 0.85);
      font-size: 13px;
      font-family: 'Consolas', monospace;
    }

    .info-value {
      color: #ffffff;
      font-size: 15px;
      font-family: 'Consolas', monospace;
      letter-spacing: 0.5px;
      padding-left: 14px;
      position: relative;
      text-shadow: 0 0 5px rgba(0, 180, 255, 0.3);
      transition: all 0.3s;

      &::before {
        content: '';
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 8px;
        height: 1px;
        background: rgba(0, 180, 255, 0.5);
      }
    }

    .status-indicator {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      position: relative;
      width: 50px;
      height: 50px;

      &.connected {
        .status-icon {
          filter: drop-shadow(0 0 3px #00ff4c);
        }

        /* .status-pulse {
        border: 2px solid rgba(0, 255, 76, 0.7);
        animation: pulse-green 2s infinite;
      }  */
        .status-text {
          color: #01AA78;
        }
      }

      &.disconnected {
        .status-icon {
          filter: drop-shadow(0 0 3px #ff4545);
        }

        /*   .status-pulse {
        border: 2px solid rgba(255, 69, 69, 0.7);
        animation: pulse-red 2s infinite;
      }      */
        .status-text {
          color: #DD675E;
        }
      }
    }

    .status-icon {
      width: 24px;
      height: 24px;
      position: relative;
      z-index: 2;
      margin-bottom: 5px;
    }

    .status-text {
      font-size: 12px;
      font-weight: 500;
      letter-spacing: 0.5px;
      font-family: 'Consolas', monospace;
      position: relative;
      z-index: 2;
      white-space: nowrap;
    }

    .status-pulse {
      position: absolute;
      top: 12px;
      /* 调整位置以匹配图标 */
      left: 50%;
      transform: translate(-50%, -50%);
      width: 30px;
      height: 30px;
      border-radius: 50%;
      opacity: 0;
    }

    .node-actions {
      display: flex;
      gap: 10px;
      margin-top: 5px;
    }
  }
  .inject-success{
    color: #01AA78 !important;
  }
  .inject-error {
    color: #DD675E !important;
  } 
}

.form-hint {
  font-size: 12px;
  color: #8b9ba9;
  margin-left: 10px;
  display: inline-block;
}
</style>